﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Data.SqlClient;
using Microsoft.Reporting.WinForms;

namespace SSRSViewer
{
    public partial class ReportViewer : UserControl
    {
        log4net.ILog log = log4net.LogManager.GetLogger(typeof(ReportViewer));
        SqlConnection DatabaseConnection { get; set; }
        RdlParser ReportParser { get; set; }
        Stream Report { get; set; }

        public event EventHandler ReportPrinted;

        public ReportViewer()
        {
            InitializeComponent();
            btnRunReport.Click += new EventHandler(btnRunReport_Click);
            viewer.Print += new CancelEventHandler(viewer_Print);
            viewer.RenderingComplete += new RenderingCompleteEventHandler(viewer_RenderingComplete);
        }

        void viewer_RenderingComplete(object sender, RenderingCompleteEventArgs e)
        {
            viewer.SetDisplayMode(DisplayMode.PrintLayout);
        }

        void viewer_Print(object sender, CancelEventArgs e) { OnPrint(); }
        void OnPrint()
        {
            var Handler = ReportPrinted;
            if (Handler != null)
                Handler(this, new EventArgs());
        }

        void btnRunReport_Click(object sender, EventArgs e)
        {
            if (Report == null)
                return;

            viewer.Clear();
            Report.Seek(0, 0);
            viewer.LocalReport.LoadReportDefinition(Report);

            BuildDatasources();
            BuildReportParameters();
            viewer.RefreshReport();
        }

        void BuildReportParameters()
        {
            List<ReportParameter> parameters = new List<ReportParameter>();
            ReportParser.ReportParameters.ToList().ForEach(p =>
                {
                    if (p.ParameterEntryUserControl is MultipleValidValuesUserControl)
                        parameters.Add(new ReportParameter(p.Name, (p.Value as object[]).Cast<string>().ToArray()));
                    else
                        parameters.Add(new ReportParameter(p.Name, p.Value.ToString()));
                });
            viewer.LocalReport.SetParameters(parameters);
        }
        void BuildDatasources()
        {
            viewer.LocalReport.DataSources.Clear();

            foreach (var dataprovider in ReportParser.DataProviders)
            {
                ReportDataSource rptDatasource = new ReportDataSource(dataprovider.Name);
                viewer.LocalReport.DataSources.Add(rptDatasource);

                SqlCommand cmd = new SqlCommand(dataprovider.CommandText, DatabaseConnection);
                dataprovider.ParameterMappings.ToList().ForEach(kp =>
                {
                    RdlReportParameter rptParameter = ReportParser.ReportParameters.Where(rp => rp.Name.ToUpper() == kp.Key.ToUpper()).SingleOrDefault();

                    if (rptParameter.ParameterEntryUserControl is MultipleValidValuesUserControl)
                    {
                        string[] values = (rptParameter.Value as object[]).Select(s => "'" + s.ToString() + "'").ToArray();
                        cmd.CommandText = cmd.CommandText.Replace(kp.Value, string.Join(",", values));
                    }
                    else
                    {
                        SqlParameter param = new SqlParameter() { ParameterName = kp.Value };
                        param.Value = rptParameter.Value;
                        param.DbType = rptParameter.GetSqlType;
                        cmd.Parameters.Add(param);
                    }
                });
                SqlDataAdapter da = new SqlDataAdapter(cmd);
                DataSet ds = new DataSet();

                if (DatabaseConnection.State != ConnectionState.Open)
                    DatabaseConnection.Open();

                da.Fill(ds);
                DatabaseConnection.Close();
                rptDatasource.Value = ds.Tables[0];
            }
        }

        /// <summary>
        /// </summary>
        /// <param name="connection"></param>
        /// <exception cref="ArgumentNullException" />
        public void Initialize(IDbConnection connection)
        {
            if (connection == null)
                throw new ArgumentNullException("connection");

            DatabaseConnection = connection as SqlConnection;
        }
        public void LoadDefinition(string stream)
        {
            MemoryStream ms = new MemoryStream();
            byte[] buffer = System.Text.Encoding.ASCII.GetBytes(stream);
            ms.Write(buffer, 0, buffer.Length);
            LoadDefinition(ms);
        }
        public void LoadDefinition(Stream stream)
        {
            try
            {
                Report = null;
                ReportParser = null;

                viewer.Clear();

                Report = stream;
                ReportParser = new RdlParser(stream, DatabaseConnection);

                pnlParameters.Controls.Clear();
                ReportParser.ReportParameters.ToList().ForEach(rp => pnlParameters.Controls.Add(rp.ParameterEntryUserControl));

                if (ReportParser.ReportParameters.Count == 0)
                    btnRunReport_Click(null, null);
            }
            catch (Exception ex)
            {
                log.Error("", ex);
                MessageBox.Show(ex.Message);
            }
        }
    }
}
